[docs] Document terminal cleanup after crash or forced stop - #1503
[docs] Document terminal cleanup after crash or forced stop#1503aspire-repo-bot[bot] wants to merge 1 commit into
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Frontend HTML artifact readyThe latest frontend build uploaded the This comment updates automatically when a new frontend build artifact is uploaded. |
There was a problem hiding this comment.
Pull request overview
Adds documentation to the existing WithTerminal AppHost page describing how terminal host Unix domain sockets are cleaned up after graceful stops, crashes/forced termination, and reboots/unclean shutdowns—reflecting the resilience improvements introduced in microsoft/aspire#19344.
Changes:
- Added a new “Terminal cleanup after a crash or forced stop” section to explain automatic socket lifecycle behavior.
- Documented both crash/forced-stop self-exit behavior and next-startup orphan socket sweeping.
- Clarified that the cleanup behavior applies in run mode, not publish mode.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
||
| Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings: | ||
|
|
||
| - If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting. |
David Pine (IEvangelist)
left a comment
There was a problem hiding this comment.
Automated docs-accuracy review — Phases A + B
Phase A source of truth: microsoft/aspire release/13.5 @ 8ab6999850d96e0023670799edbd4bdc245ad63c (matches this PR's target branch release/13.5). Cross-checked against microsoft/aspire main @ 0cedb24b5a7e7f83887e7585e19ae47fbbe6af5d for context only.
Claims extracted: 6 → verified 2, verified-with-nuance 0, unverifiable 4, contradicted 0 (verdicts are against the target branch release/13.5).
Phase B: 1 route exercised (/app-host/with-terminal/) served from PR head b661eaa4 — 0 critical, 1 warning, 2 knowledge gaps.
⚠️ Key finding — version targetingEvery resilience behavior this section documents — signal-driven socket unlink, the parent-process watchdog, and the startup orphan sweep — was introduced by microsoft/aspire#19344 ("Handle SIGTERM in terminal host and GC orphaned sockets"), which is milestone
13.6, merged tomainonly. Its merge commitb777bb16is not an ancestor ofrelease/13.5, and none of the new symbols (TerminalHostProcessRunner,TerminalHostOrphanCleanupService, the terminal-hostParentProcessWatchdogwiring) exist onrelease/13.5.So on the branch this PR targets (
release/13.5), claims C3–C6 areunverifiable— the prose is factually accurate, but it describes 13.6 behavior on the 13.5 docs branch. Please confirm this section is intended to ship with 13.5, or retarget it to the 13.6 docs once that branch exists. Claims C1–C2 (socket location + cleanup on normal stop) are already true onrelease/13.5.
Phase A — Claim verification
The 4 unverifiable claims are posted as inline comments on their lines. The 2 verified claims are listed below.
Verified claims (2) — evidence on release/13.5
- C1 — per-replica Unix domain socket under
~/.aspire/trmnl/(line 172):verified.src/Shared/TerminalHost/TerminalHostPaths.csdefinesTrmnlDirectoryName = "trmnl"and the socket path format{home}/.aspire/trmnl/{replicaId}.{sockPurpose}.sock;src/Aspire.Hosting/TerminalResourceBuilderExtensions.cs(L156–176) creates the files flat under~/.aspire/trmnl/. Minor nuance: each replica actually has two sockets (control + consumer) plus ametadata.jsonsidecar, so "a per-replica Unix domain socket" (singular) is a small simplification. Not blocking. - C2 — automatic cleanup on normal stop (line 172):
verified.src/Aspire.Hosting/TerminalResourceBuilderExtensions.cs(L270–293) registersIHostApplicationLifetime.ApplicationStopped→DeleteReplicaFiles(...), and the host children unlink their own UDS endpoints on graceful shutdown (comment at L273–275).
Phase B — Doc-tester results
Produced by the
doc-testerskill (blind to source code), navigating the local dev server (http://localhost:4321/) serving PR headb661eaa4via Playwright.
Documentation Test Report
Focus Area: New section "Terminal cleanup after a crash or forced stop" on /app-host/with-terminal/
Date: 2026-08-15
Tester: doc-tester agent
Server / ref: http://localhost:4321/ serving PR head b661eaa4 (branch pr-1503)
Routes exercised: /app-host/with-terminal/ → section #terminal-cleanup-after-a-crash-or-forced-stop
Summary
| Category | Passed | Failed | Warnings |
|---|---|---|---|
| Content Accuracy | 1 | 0 | 1 |
| Code Examples | n/a (none in section) | 0 | 0 |
| CLI Commands | n/a (none in section) | 0 | 0 |
| Links / Anchors | 1 | 0 | 0 |
Critical Issues
None.
Warnings
Warning 1: "run mode" / "publish mode" used without explanation or link
Location: /app-host/with-terminal/#terminal-cleanup-after-a-crash-or-forced-stop, closing paragraph.
Issue: The final sentence distinguishes run mode and publish mode — Aspire-specific concepts — but neither is linked or explained on this page (each term appears exactly once, only in this new section, with no cross-reference; 64 links on the page, none pointing at a run/publish-mode concept). A first-time reader may not know what publish mode is or why terminal hosts wouldn't be materialized there.
Suggestion: Link "publish mode" / "run mode" to their concept page on first use.
Passed Checks
- Section renders correctly:
<h2>heading, table-of-contents entry, and self-anchor link (#terminal-cleanup-after-a-crash-or-forced-stop) are all present and functional. - Prose renders as one intro paragraph, a 3-item bullet list, and a closing paragraph; smart quotes and em-dashes render correctly; no raw markdown leaks into the page.
- No console errors on page load (0 errors / 0 warnings).
- Section is internally self-consistent and readable; the prerequisite terms "terminal host" and "replica" are introduced earlier on the same page (intro + "Terminals and replicas" section).
Knowledge Gaps
Knowledge Gap: SIGTERM / Unix domain socket
What I needed to know: what SIGTERM and a "Unix domain socket" are.
Source of my knowledge: Built-in/prior knowledge (NOT from documentation).
User impact: Developers from non-Unix / non-systems backgrounds may not recognize these. SIGTERM is softened by the "docker stop / process manager" example, which helps.
Recommendation: Reasonable to assume for this audience; optionally gloss "Unix domain socket."
Knowledge Gap: runtime behavior could not be reproduced
What I needed to do: Confirm sockets are actually removed after SIGTERM / crash / reboot.
Why blocked: WithTerminal is experimental and the doc states the sockets live on Linux and macOS; this test host is Windows, so ~/.aspire/trmnl/ socket cleanup cannot be exercised here. Per doc-tester rules I did not read source to fill this gap.
User impact: None to the reader — recorded as a tester limitation so the "blind user" runtime verification of this section is explicitly noted as incomplete.
Recommendations
- Priority fixes: None (no critical issues).
- Documentation gaps: Link run/publish mode on first use.
- Product issues: None discovered.
Verdict: COMMENT
No contradicted claims and no Phase B critical issues, so this is not REQUEST_CHANGES. It is not APPROVE because 4 claims are unverifiable on the target branch (the documented 13.6 feature is absent from release/13.5) and Phase B raised a warning + knowledge gaps. The prose itself is accurate against the code where the feature actually lives (main/13.6); the actionable item is the version-targeting question above.
|
|
||
| Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings: | ||
|
|
||
| - If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting. |
There was a problem hiding this comment.
C3 · unverifiable on the target branch (release/13.5).
If the AppHost sends
SIGTERM… or you interrupt it withCtrl+C, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting.
On microsoft/aspire release/13.5 (8ab6999) the terminal host has no SIGTERM/SIGINT handling — src/Aspire.TerminalHost/ contains no PosixSignal registration. This behavior was added by microsoft/aspire#19344 (milestone 13.6, base main): src/Aspire.TerminalHost/TerminalHostProcessRunner.cs (L45–89) registers SIGINT+SIGTERM and the first signal grants the host a bounded window to unlink its sockets. Accurate against main; absent on release/13.5.
| Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings: | ||
|
|
||
| - If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting. | ||
| - If the AppHost process itself crashes or is killed without giving its children a chance to shut down, each terminal host detects that its parent process is gone and exits on its own shortly after. |
There was a problem hiding this comment.
C4 · unverifiable on the target branch (release/13.5).
each terminal host detects that its parent process is gone and exits on its own shortly after.
No parent-process watchdog is wired into the terminal host on release/13.5. Added by microsoft/aspire#19344 (13.6): TerminalHostProcessRunner.cs (L23–27) starts ParentProcessWatchdog.Start(..., TerminalHostParentProcessId, ...), and src/Shared/ParentProcessWatchdog.cs (L9–63) cancels and force-exits (5 s grace, exit code 124) once the parent PID is no longer alive. Accurate against main; absent on release/13.5.
|
|
||
| - If the AppHost sends `SIGTERM` (for example, `docker stop` or a process manager shutting things down) or you interrupt it with `Ctrl+C`, the terminal host receives the signal, cancels its work, and unlinks its own socket before exiting. | ||
| - If the AppHost process itself crashes or is killed without giving its children a chance to shut down, each terminal host detects that its parent process is gone and exits on its own shortly after. | ||
| - On the next AppHost startup, a background sweep reclaims any sockets left behind by replicas whose owning process is confirmed gone—for example, after a machine reboot or an unclean shutdown. Sockets belonging to a process that might still be running (or that Aspire can't confirm has exited) are left alone. |
There was a problem hiding this comment.
C5 · unverifiable on the target branch (release/13.5).
a background sweep reclaims any sockets left behind by replicas whose owning process is confirmed gone … Sockets belonging to a process that might still be running (or that Aspire can't confirm has exited) are left alone.
There is no orphan-cleanup service on release/13.5. Added by microsoft/aspire#19344 (13.6): src/Aspire.Hosting/Lifecycle/TerminalHostOrphanCleanupService.cs — a BeforeStartEvent sweep (L61) that reclaims only confirmed-dead owners: ownerIsRunning → continue (L365–367) and unableToInspectOwner → continue with "leaving its artifacts in place" (L356–363), so only a confirmed-not-running owner reaches DeleteReplicaFiles (L374). The prose matches this implementation precisely. Accurate against main; absent on release/13.5.
| - If the AppHost process itself crashes or is killed without giving its children a chance to shut down, each terminal host detects that its parent process is gone and exits on its own shortly after. | ||
| - On the next AppHost startup, a background sweep reclaims any sockets left behind by replicas whose owning process is confirmed gone—for example, after a machine reboot or an unclean shutdown. Sockets belonging to a process that might still be running (or that Aspire can't confirm has exited) are left alone. | ||
|
|
||
| You don't need to do anything to benefit from this—it runs automatically in run mode. It doesn't apply to publish mode, since publish never materializes terminal hosts or their sockets. |
There was a problem hiding this comment.
C6 · unverifiable on the target branch (release/13.5).
it runs automatically in run mode. It doesn't apply to publish mode, since publish never materializes terminal hosts or their sockets.
The cleanup service this sentence describes does not exist on release/13.5. On main (via microsoft/aspire#19344, 13.6) the sweep subscribes only when executionContext.IsRunMode (TerminalHostOrphanCleanupService.cs L57), so the run-mode-only framing is correct there. Accurate against main; the described cleanup is absent on release/13.5.
|
|
||
| ## Terminal cleanup after a crash or forced stop | ||
|
|
||
| Each terminal host listens on a per-replica Unix domain socket under `~/.aspire/trmnl/` on Linux and macOS. Aspire cleans these sockets up automatically when a resource stops normally, but it's also resilient to less graceful endings: |
There was a problem hiding this comment.
This is actually three sockets per replica (producer, consumer, and control), and the cleanup code removes all three. Could we use plural wording here? “a per-replica Unix domain socket” makes the cleanup model inaccurate.
|
I am not sure what is the value of having this in the documentation. These socket files are just implementation details. |
Documents changes from microsoft/aspire#19344
@IEvangelistTargeting
release/13.5— the latest release branch onmicrosoft/aspire.dev— becauserelease/13.6(from the source PR milestone13.6) does not exist there.Why this PR is needed
microsoft/aspire#19344 makes
WithTerminal()socket cleanup resilient across graceful stops (SIGTERM/Ctrl+C), forced termination, AppHost crashes, and reboots, adding a new publicTerminalHostProcessRunnerrunner class and a background orphan-cleanup service. This is a user-visible reliability improvement (no more leaked sockets under~/.aspire/trmnl/) for a feature (WithTerminal) that already has a dedicated docs page, but that page didn't previously mention cleanup/lifecycle behavior at all.What changed
Added a new "Terminal cleanup after a crash or forced stop" section to
app-host/with-terminal.mdx, explaining:Files modified
src/frontend/src/content/docs/app-host/with-terminal.mdx— added a new section, no existing content changed.No new pages were created; this is an addition to the existing
WithTerminalpage.